home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianScripts.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  54KB  |  2,773 lines

  1. /*ScianScripts.c
  2.   Stuff for scripts in scian
  3.   Eric Pepke
  4. */
  5.  
  6. #include "Scian.h"
  7. #include "ScianTypes.h"
  8. #include "ScianArrays.h"
  9. #include "ScianIDs.h"
  10. #include "ScianEvents.h"
  11. #include "ScianRecorders.h"
  12. #include "ScianColors.h"
  13. #include "ScianWindows.h"
  14. #include "ScianObjWindows.h"
  15. #include "ScianDialogs.h"
  16. #include "ScianVisWindows.h"
  17. #include "ScianScripts.h"
  18. #include "ScianSliders.h"
  19. #include "ScianTimers.h"
  20. #include "ScianMethods.h"
  21. #include "ScianLists.h"
  22. #include "ScianErrors.h"
  23. #include "ScianGarbageMan.h"
  24. #include "ScianSpaces.h"
  25. #include "ScianIcons.h"
  26. #include "ScianSockets.h"
  27. #include "ScianObjFunctions.h"
  28. #include "ScianGlobalFunctions.h"
  29. #include "ScianCurrentFunctions.h"
  30. #include "ScianWindowFunctions.h"
  31. #include "ScianRepobjFunctions.h"
  32. #include "ScianHelp.h"
  33. #include "ScianStyle.h"
  34. #include "ScianNames.h"
  35. #include "ScianTextFiles.h"
  36. #include "ScianDatabase.h"
  37. #include "ScianSymbols.h"
  38.  
  39. Bool runningScript = false;        /*True iff running script*/
  40. Bool settingUp = false;            /*True iff setting up*/
  41. WinInfoPtr scriptWindow = 0;        /*The current window of the script*/
  42. extern ObjPtr perspecControlClass;    /*Class of perspecive controls*/
  43. long framesLeft = 0;            /*Frames left to record*/
  44. Bool abortScript = false;        /*Abort script*/
  45. TextFilePtr curScript = 0;        /*Current script being read, if any*/
  46. char *scriptLine = 0;            /*Current line of the script*/
  47. Bool lineAccepted = true;        /*True iff last script line was accepted*/
  48. int inhibitRecording = 0;        /*Inhibits recording*/
  49.  
  50. TextFilePtr savedScripts[10];        /*Stack for saving scripts*/
  51. int curScriptIndex = 0;
  52.  
  53. /*IDs for running tasks*/
  54. #define RT_NONE        0        /*No running task*/
  55. #define RT_RECORDING    1        /*Recording some time*/
  56. int runningTask = RT_NONE;        /*Current running task*/
  57.  
  58. #define MAXSTACKDEPTH    100        /*Maximum depth of block stack*/
  59.  
  60. /*Block in a stack*/
  61. typedef struct
  62.     {
  63.     int command;            /*The command*/
  64.     ObjPtr object;            /*The (optional) object this is about*/
  65.     } Block;
  66.  
  67. Block commandStack[MAXSTACKDEPTH];    /*Stack of commands*/
  68. int nextStackElement = 0;        /*Next element on the stack*/
  69.  
  70. typedef struct                /*Element of file logging stack*/
  71.     {
  72.     FILE *logFile;            /*File pointer for logging*/
  73.     int logInhibit;            /*Counter to inhibit logging*/
  74.     WinInfoPtr logWindow;        /*Current window set in log*/
  75.     } LogElement;
  76.  
  77. #define MAXLOGFILES    50        /*Maximum number of log files open*/
  78.  
  79. LogElement logStack[MAXLOGFILES];    /*Stack of log files*/
  80. int nextLogElement = 0;            /*Next element on the stack*/
  81.  
  82. #define KWBEGIN        0    /*Begin a block*/
  83. #define KWEND        1    /*End current modal command*/
  84. #define KWRECORDER    2    /*(set) recorder*/
  85. #define KWDESELECT    3    /*Deselect an icon*/
  86. #define KWSELECT    4    /*Select an icon*/
  87. #define KWSHELL        5    /*Shell escape*/
  88. #define KWALIGNMENT    6    /*(Set) alignment OBSELETE*/
  89. #define KWLOCATION    7    /*(Set) location*/
  90. #define KWVIDEOSCREEN    8    /*Resize current window to video screen*/
  91. #define KWFULLSCREEN    9    /*Resize current window to full screen*/
  92. #define KWROTATE    10    /*Rotate space*/
  93. #define KWSHOW        11    /*Show something*/
  94. #define KWPANEL        12    /*(Show/Hide) the panel of icons*/
  95. #define KWRECORDING    13    /*(Begin/End) recording*/
  96. #define KWSNAP        14    /*Snap a single frame*/
  97. #define KWWINDOW    15    /*Select a new window*/
  98. #define KWSET        16    /*Set something*/
  99. #define KWCONTROLS    17    /*(Show) controls for a vis object*/
  100. #define KWPUSHWINDOW    18    /*Push a window behind all others*/
  101. #define KWQUIT        19    /*Quit*/
  102. #define KWSHEAR        20    /*Shear the matrix*/
  103. #define KWFPS        21    /*(Set) fps*/
  104. #define KWEYEPOSN    22    /*Eye position*/
  105. #define KWROLL        23    /*Roll of eyeball*/
  106. #define KWPITCH        24    /*Pitch of eyeball*/
  107. #define KWYAW        25    /*Yaw of eyeball*/
  108. #define KWRECTANGLE    26    /*Rectangle*/
  109. #define KWHIDE        27    /*Hide the frame of a window*/
  110. #define KWEXIT        28    /*Exit on next loop*/
  111. #define KWVALUE        29    /*(Set) value of a something*/
  112. #define KWFONT        30    /*(Set) the font of something OBSELETE*/
  113. #define KWSIZE        31    /*(Set) the size of something's font OBSELETE*/
  114. #define KWCLOSE        32    /*Closes a window*/
  115. #define KWENDPOINTS    33    /*(Set) endpoints*/
  116. #define KWDROP        34    /*Drops whatever is in the drag buffer*/
  117. #define KWBOUNDS    35    /*(Set) the bounds of an object*/
  118. #define KWTILE        36    /*Tile to a certain width and height*/
  119. #define KWANNOTATION    37    /*Add annotation*/
  120. #define KWFRAME        38    /*(Show/Hide) the frame of a window*/
  121. #define KWLOCATE    39    /*Locate a window*/
  122. #define KWDELETE    40    /*Delete stuff*/
  123. #define KWSCRSAVE    41    /*Save the screen*/
  124. #define KWRECORD    42    /*Record some number of seconds*/
  125. #define KWSCREEN    43    /*(Set) screen*/
  126. #define KWCOLOR        44    /*(Set) color*/
  127. #define KWPREFERENCES    45    /*(Show) preferences*/
  128. #define KWTIME        46    /*Time*/
  129. #define KWOFF        47    /*(Turn) off*/
  130. #define KWTURN        48    /*Turn (on/off)*/
  131. #define KWON        49    /*(Turn) on*/
  132. #define KWLINE        50    /*Make a new line*/
  133. #define KWFUNCTIONBOX    51    /*(Set) Function box*/
  134. #define KWFILESWINDOW    52    /*(Show) FilesWindow*/
  135. #define KWSELECTALL    53    /*Selectall*/
  136. #define KWDESELECTALL    54    /*Deselectall*/
  137. #define KWHELP        55    /*(Show) help*/
  138. #define KWFILEREADERS   56    /*(Show) fileReaders*/
  139. #define KWDATASETS    57    /*(Show) datasets*/
  140. #define KWROTATION    58    /*(Set) rotation*/
  141. #define KWVERSION    59    /*Version*/
  142. #define KWFRONT        60    /*(Show) front (panel controls)*/
  143. #define KWBACK        61    /*(Show) back (panel controls)*/
  144. #define KWSETUP        62    /*(Begin/End) setup*/
  145. #define KWSAVE        63    /*Save something*/
  146. #define KWTIMEREADOUT    64    /*Make a time readout*/
  147. #define KWSPACE        65    /*(Show) space (controls)*/
  148. #define KWEFFECT    66    /*Color special effect OBSELETE*/
  149. #define KWKEEP        67    /*Keep changes to palette OBSELETE*/
  150. #define KWREVERT    68    /*Revert to last saved palette OBSELETE*/
  151. #define KWMODEL        69    /*Color model OBSELETE*/
  152. #define KWSNAPSHOT    70    /*(Begin) Snapshot*/
  153. #define KWOBSERVER    71    /*(Begin Snapshot) Observer*/
  154. #define KWVARIABLE    72    /*(set) Variable <value>*/
  155. #define KWOBJECT    73    /*(Begin Snapshot) */
  156. #define KWRECORDERS    74    /*recorders*/
  157. #define KWSCRIPT    75    /*Begin/end script, used for nesting scripts*/
  158. #define NKEYWORDS    76    /*Number of keywords*/
  159.  
  160.  
  161. char *keywords[NKEYWORDS] =
  162.     {
  163.         "begin",
  164.         "end",
  165.         "recorder",
  166.         "deselect",
  167.         "select",
  168.         "shell",
  169.         "alignment",
  170.         "location",
  171.         "videoscreen",
  172.         "fullscreen",
  173.         "rotate",
  174.         "show",
  175.         "panel",
  176.         "recording",
  177.         "snap",
  178.         "window",
  179.         "set",
  180.         "controls",
  181.         "pushwindow",
  182.         "quit",
  183.         "shear",
  184.         "fps",
  185.         "eyeposn",
  186.         "roll",
  187.         "pitch",
  188.         "yaw",
  189.         "rectangle",
  190.         "hide",
  191.         "exit",
  192.         "value",
  193.         "font",
  194.         "size",
  195.         "close",
  196.         "endpoints",
  197.         "drop",
  198.         "bounds",
  199.         "tile",
  200.         "annotation",
  201.         "frame",
  202.         "locate",
  203.         "delete",
  204.         "scrsave",
  205.         "record",
  206.         "screen",
  207.         "color",
  208.         "preferences",
  209.         "time",
  210.         "off",
  211.         "turn",
  212.         "on",
  213.         "line",
  214.         "functionbox",
  215.         "fileswindow",
  216.         "selectall",
  217.         "deselectall",
  218.         "help",
  219.         "filereaders",
  220.         "datasets",
  221.         "rotation",
  222.         "version",
  223.         "front",
  224.         "back",
  225.         "setup",
  226.         "save",
  227.         "timereadout",
  228.         "space",
  229.         "effect",
  230.         "keep",
  231.         "revert",
  232.         "model",
  233.         "snapshot",
  234.         "observer",
  235.         "variable",
  236.         "object",
  237.         "recorders",
  238.         "script"
  239.     };
  240.  
  241. char *classNames[N_CLASS_IDS] = 
  242.     {
  243.         "icon",
  244.         "corral",
  245.         "visWindow",
  246.         "light",
  247.         "clock",
  248.         "observer",
  249.         "renderer",
  250.         "timedObj",
  251.         "visObj",
  252.         "panel",
  253.         "dataset",
  254.         "file",
  255.         "textBox",
  256.         "space",
  257.         "dialog",
  258.         "fileReader",
  259.         "recorder",
  260.         "snapshot"
  261.     };
  262.  
  263. /*Classes, must be set by initialization routines*/
  264. ObjPtr classClasses[N_CLASS_IDS] =
  265.     {
  266.     NULLOBJ,
  267.     NULLOBJ,
  268.     NULLOBJ,
  269.     NULLOBJ,
  270.     NULLOBJ,
  271.     NULLOBJ,
  272.     NULLOBJ,
  273.     NULLOBJ,
  274.     NULLOBJ,
  275.     NULLOBJ,
  276.     NULLOBJ,
  277.     NULLOBJ,
  278.     NULLOBJ,
  279.     NULLOBJ,
  280.     NULLOBJ,
  281.     NULLOBJ,
  282.     NULLOBJ,
  283.     NULLOBJ
  284.     };
  285.  
  286. char *begToken, *endToken;    /*Beginning and ending of current token*/
  287.  
  288. #ifdef PROTO
  289. Bool BeginCommand(char *);
  290. Bool EndCommand(char *);
  291. #else
  292. Bool BeginCommand();
  293. Bool EndCommand();
  294. #endif
  295.  
  296. FILE *OpenLogFile(name)
  297. char *name;
  298. /*Opens a log file named name in the current directory.  OpenLogFile and
  299.   CloseLogFile may be nested.  If !name, it's stdout*/
  300. {
  301.     struct timeval date;
  302.  
  303.     if (name)
  304.     {
  305.     logStack[nextLogElement] . logFile = fopen(name, "w");
  306.     }
  307.     else
  308.     {
  309.     logStack[nextLogElement] . logFile = stdout;
  310.     }
  311.  
  312.     if (logStack[nextLogElement] . logFile)
  313.     {
  314.     logStack[nextLogElement] . logInhibit = 0;
  315.     logStack[nextLogElement] . logWindow = 0;
  316.     }
  317.     else
  318.     {
  319.     WinInfoPtr alertWindow;
  320.     char msg[300];
  321.     getcwd(tempStr, TEMPSTRSIZE);
  322.  
  323.     sprintf(msg, "File %s cannot be saved in directory %s.",
  324.         name, tempStr);
  325.     alertWindow = AlertUser(UIERRORALERT, (WinInfoPtr) NULLOBJ,
  326.             msg, (FuncTyp) 0, 1, "Oh Well");
  327.     SetVar((ObjPtr) alertWindow, HELPSTRING,
  328.         NewString("A file cannot be saved in the specified directory.  \
  329. This is probably because the permissions on the directory are not set up to allow \
  330. you to write to it.  Check the permissions on the directory and try again."));
  331.     SetVar((ObjPtr) alertWindow, INHIBITLOGGING, ObjTrue);
  332.     return 0;
  333.     }
  334.  
  335.     /*Write out a version number as first line in file*/
  336.     fprintf(logStack[nextLogElement] . logFile, "%s\n", SCIANVERSION);
  337.  
  338.     /*And a time stamp*/
  339.     gettimeofday(&date, (struct timezone *)0);
  340.  
  341.     fprintf(logStack[nextLogElement] . logFile, "time %s\n", ctime(&date.tv_sec));
  342.  
  343.     return logStack[nextLogElement++] . logFile;
  344. }
  345.  
  346. void CloseLogFile()
  347. /*Closes a log file opened by OpenLogFile.*/
  348. {
  349.     if (!nextLogElement) return;
  350.     --nextLogElement;
  351.     if (logStack[nextLogElement] . logFile != stdout)
  352.     {
  353.     fclose(logStack[nextLogElement] . logFile);
  354.     }
  355. }
  356.  
  357. void CloseAllLogFiles()
  358. /*Closes all log files*/
  359. {
  360.     while (nextLogElement) CloseLogFile();
  361. }
  362.  
  363. Bool logBeginning = true;    /*True iff it's at the beginning of a log line*/
  364.  
  365. Bool AnyLogging()
  366. /*Returns true iff any logging is to be done*/
  367. {
  368.     if (!nextLogElement)
  369.     {
  370.     return false;
  371.     }
  372.  
  373.     if (logStack[nextLogElement - 1] . logInhibit)
  374.     {
  375.     return false;
  376.     }
  377.     return true;
  378. }
  379.  
  380. void Log(s)
  381. char *s;
  382. /*Logs command s to all the open log files*/
  383. {
  384.     int whichLog;
  385.     char *t;
  386.  
  387.     if (selWinInfo && GetPredicate((ObjPtr) selWinInfo, INHIBITLOGGING))
  388.     {
  389.     return;
  390.     }
  391.  
  392.     if (!nextLogElement) return;
  393.  
  394.     for (whichLog = nextLogElement - 1; whichLog >= 0; --whichLog)
  395.     {
  396.     if (logStack[whichLog] . logInhibit)
  397.     {
  398.         /*Done; don't do no more.*/
  399.         break;
  400.     }
  401.         
  402.     if (logBeginning && selWinInfo && logStack[whichLog] . logWindow != selWinInfo)
  403.     {
  404.         /*Make a window command*/
  405.         char windowName[256];
  406.         int k;
  407.  
  408.         /*Copy window title*/
  409.         t = selWinInfo -> winTitle;
  410.         k = 0;
  411.         while (*t)
  412.         {
  413.         if (*t == ' ')
  414.         {
  415.             windowName[k++] = '_';
  416.             ++t;
  417.         }
  418.         else
  419.         {
  420.             if (!isalpha(*t) && ((k == 0) || !isdigit(*t)))
  421.             {
  422.             windowName[k++] = '\\';
  423.             }
  424.             windowName[k++] = *t++;
  425.         }
  426.         }
  427.         windowName[k] = 0;
  428.  
  429.         fprintf(logStack[whichLog] . logFile, "window %s\n", windowName);
  430.         logStack[whichLog] . logWindow = selWinInfo;
  431.     }
  432.     fputs(s, logStack[whichLog] . logFile);
  433.     }
  434.     /*Determine if it's in a line*/
  435.     t = s;
  436.     if (*t)
  437.     {
  438.         while (*t) ++t;
  439.         --t;
  440.         if (*t == '\n')
  441.         {
  442.         logBeginning = true;
  443.         }
  444.         else
  445.         {
  446.         logBeginning = false;
  447.         }
  448.     }
  449. }
  450.  
  451. void LogNoWindow(s)
  452. char *s;
  453. /*Logs command s to all the open log files, with no window command*/
  454. {
  455.     int whichLog;
  456.     char *t;
  457.  
  458.     for (whichLog = nextLogElement - 1; whichLog >= 0; --whichLog)
  459.     {
  460.     if (logStack[whichLog] . logInhibit)
  461.     {
  462.         /*Done; don't do no more.*/
  463.         break;
  464.     }
  465.         
  466.     fputs(s, logStack[whichLog] . logFile);
  467.     }
  468.     /*Determine if it's in a line*/
  469.     t = s;
  470.     if (*t)
  471.     {
  472.         while (*t) ++t;
  473.         --t;
  474.         if (*t == '\n')
  475.         {
  476.         logBeginning = true;
  477.         }
  478.         else
  479.         {
  480.         logBeginning = false;
  481.         }
  482.     }
  483. }
  484.  
  485. #ifdef PROTO
  486. void InhibitLogging(Bool whether)
  487. #else
  488. void InhibitLogging(whether)
  489. Bool whether;
  490. #endif
  491. /*Inhibits or disinhibits logging based on whether*/
  492. {
  493.     if (nextLogElement)
  494.     {
  495.     if (whether)
  496.     {
  497.         ++logStack[nextLogElement - 1] . logInhibit;
  498.     }
  499.     else
  500.     {
  501.         --logStack[nextLogElement - 1] . logInhibit;
  502.     }
  503.     }
  504.     if (whether)
  505.     {
  506.         ++inhibitRecording;
  507.     }
  508.     else
  509.     {
  510.         --inhibitRecording;
  511.     }
  512. }
  513.  
  514. #ifdef PROTO
  515. void LogVariable(ObjPtr object, NameTyp variable)
  516. #else
  517. void LogVariable(object, variable)
  518. ObjPtr object; NameTyp variable;
  519. #endif
  520. /*Logs a variable*/
  521. {
  522.     if (AnyLogging() && !GetPredicate(object, INHIBITLOGGING))
  523.     {
  524.     char cmd[256];
  525.     char *s;
  526.     ObjPtr value;
  527.  
  528.     value = GetVar(object, variable);
  529.  
  530.     if (IsInt(value))
  531.     {
  532.         sprintf(cmd, "    set variable %s (int) ", GetInternalString(variable));
  533.     }
  534.     else
  535.     {
  536.         sprintf(cmd, "    set variable %s ", GetInternalString(variable));
  537.     }
  538.     s = &(cmd[0]);
  539.     while (*s) ++s;
  540.     PrintScriptObject(s, value);
  541.     while (*s) ++s;
  542.     *s++ = '\n';
  543.     *s = 0;
  544.     Log(cmd);
  545.     }
  546. }
  547.  
  548. void LogControl(object)
  549. ObjPtr object;
  550. {
  551.     ObjPtr repObj;
  552.     ObjPtr var;
  553.     NameTyp whichVar;
  554.  
  555.     if (GetPredicate(object, INHIBITLOGGING)) return;
  556.  
  557.     if (AnyLogging())
  558.     {
  559.     char cmd[256];
  560.     char *s;
  561.  
  562.     sprintf(cmd, "set value ");
  563.     s = &(cmd[0]);
  564.     while (*s) ++s;
  565.     MakeObjectName(s, object);
  566.     while (*s) ++s;
  567.     *s++ = ' ';
  568.     PrintScriptObject(s, GetVar(object, VALUE));
  569.     while (*s) ++s;
  570.     *s++ = '\n';
  571.     *s = 0;
  572.     Log(cmd);
  573.     }
  574.  
  575.     /*Record the object var, if appropriate*/
  576.  
  577.     if (GetPredicate(object, INHIBITRECORDING)) return;
  578.  
  579.     if (inhibitRecording) return;
  580.  
  581.     repObj = GetVar(object, REPOBJ);
  582.     var = GetVar(object, WHICHVAR);
  583.     if (repObj && var)
  584.     {
  585.     whichVar = GetSymbolID(var);
  586.     RecordObjectVar(repObj, whichVar);
  587.     }
  588. }
  589.  
  590. void LogObjectName(object)
  591. ObjPtr object;
  592. /*Logs the name of an object*/
  593. {
  594.     char objName[400];
  595.     PrintScriptObject(objName, object);
  596.     Log(objName);
  597. }
  598.  
  599. void LogNoWindowObjectName(object)
  600. ObjPtr object;
  601. /*Logs the name of an object*/
  602. {
  603.     char objName[400];
  604.     PrintScriptObject(objName, object);
  605.     LogNoWindow(objName);
  606. }
  607.  
  608. void ScriptError(e)
  609. char *e;
  610. /*Prints out an error e*/
  611. {
  612.     if (curScript)
  613.     {
  614.  
  615.     CurLineError(curScript, e, begToken, endToken);
  616.     if (abortScriptP)
  617.     {
  618.         abortScript = true;
  619.     }
  620.     }
  621. }
  622.  
  623. void SelectNamedWindow(name)
  624. char *name;
  625. /*Selects a window by name name*/
  626. {
  627.     WinInfoPtr namedWindow;
  628.     namedWindow = GetWinFromTitle(name);
  629.     if (!namedWindow)
  630.     {
  631.     ScriptError("Cannot find a unique window by that name.");
  632.     return;
  633.     }
  634.     SelWindow(namedWindow);
  635.     scriptWindow = namedWindow;
  636. }
  637.  
  638. static ObjPtr testObj;
  639. static WinInfoPtr repWindow;
  640. static ObjPtr globalRep;
  641.  
  642. void TestWindowOnObject(window)
  643. WinInfoPtr window;
  644. /*Tests to see if window has an object which represents testObj*/
  645. {
  646.     ObjPtr rep;
  647.     if (rep = ObjectWhichRepresents(window, testObj))
  648.     {
  649.     repWindow = window;
  650.     globalRep = rep;
  651.     }
  652. }
  653.  
  654. Bool MakeObjectName(dest, object)
  655. char *dest;
  656. ObjPtr object;
  657. /*Makes a long object name from object and puts it into dest.  Returns 
  658.   true iff the object name requires the current window.*/
  659. {
  660.     register char *s;
  661.     ObjPtr name;
  662.     ObjPtr representative = NULLOBJ;
  663.     ObjPtr keyList, resultList;
  664.     ObjPtr classID;
  665.     Bool retVal = true;
  666.  
  667.     /*See if there's an entry in the database*/
  668.     keyList = NewList();
  669.     PostfixList(keyList, NewSymbol(NAME));
  670.     PostfixList(keyList, GetVar(object, NAME));
  671.     PostfixList(keyList, NewSymbol(CLASSID));
  672.     PostfixList(keyList, classID = GetVar(object, CLASSID));
  673.     resultList = SearchDatabase(keyList);
  674.     if (classID && resultList && LISTOF(resultList) && !(LISTOF(resultList) -> next))
  675.     {
  676.     /*Unique database entry*/
  677.     strcpy(dest, classNames[GetInt(classID)]);
  678.     while (*dest) ++dest;
  679.     *dest++ = '@';
  680.     retVal = false;
  681.     }
  682.     else if (!IsWindow(object) &&
  683.     ((!IsValidWindow(selWinInfo)) ||
  684.      (!(representative = ObjectWhichRepresents(selWinInfo, object)))))
  685.     {
  686.     /*Must find a window that knows about the object*/
  687.     testObj = object;
  688.     repWindow = (WinInfoPtr) 0;
  689.  
  690.     ForAllWindows(TestWindowOnObject);
  691.  
  692.     if (repWindow)
  693.     {
  694.         representative = globalRep;
  695.         MakeObjectName(dest, (ObjPtr) repWindow);
  696.         while (*dest) ++dest;
  697.     }
  698.     else
  699.     {
  700.         *dest++ = '?';
  701.     }
  702.     *dest++ = ':';
  703.     }
  704.  
  705.     if (representative)
  706.     {
  707.     object = representative;
  708.     }
  709.  
  710.     name = GetStringVar("MakeObjectName", object, NAME);
  711.     if (!name)
  712.     {
  713.     *dest = 0;
  714.     return retVal;
  715.     }
  716.  
  717.     /*Copy name*/
  718.     s = GetString(name);
  719.     if (isdigit(*s))
  720.     {
  721.     *dest++ = '\\';
  722.     }
  723.     while (*s)
  724.     {
  725.     if (*s == ' ')
  726.     {
  727.         *dest++ = '_';
  728.         ++s;
  729.     }
  730.     else
  731.     {
  732.         if (!isalpha(*s) && !isdigit(*s))
  733.         {
  734.         *dest++ = '\\';
  735.         }
  736.         *dest++ = *s++;
  737.     }
  738.     }
  739.     *dest = 0;
  740.     return retVal;
  741. }
  742.  
  743. int ParseKeyword(s, l, n)
  744. char *s;
  745. char *l[];
  746. int n;
  747. /*Parses keyword s in list l with number of elements n.Returns its number or -1 == not found, -2 ==
  748.   ambiguious.*/
  749. {
  750.     int match = -1;        /*Last found match*/
  751.     int i, k;            /*Counters*/
  752.  
  753.     /*Seek an exact match*/
  754.     for (k = 0; k < n; ++k)
  755.     {
  756.     for (i = 0; s[i]; ++i)
  757.     {
  758.         if (tolower(s[i]) != tolower(l[k][i]))
  759.         {
  760.         break;
  761.         }
  762.     }
  763.     if (!s[i] && !keywords[k][i])
  764.     {
  765.         /*It's a match!*/
  766.         return k;
  767.     }
  768.     }
  769.  
  770.     /*Seek a partial match*/
  771.     for (k = 0; k < n; ++k)
  772.     {
  773.     for (i = 0; s[i]; ++i)
  774.     {
  775.         if (tolower(s[i]) != tolower(l[k][i]))
  776.         {
  777.         break;
  778.         }
  779.     }
  780.     if (!s[i])
  781.     {
  782.         /*It's a match!*/
  783.         if (match >= 0)
  784.         {
  785.         /*Double match*/
  786.         return -2;
  787.         }
  788.         match = k;
  789.     }
  790.     }
  791.     return match;
  792. }
  793.  
  794. #ifdef PROTO
  795. char *ParseArray(char *s, ObjPtr *o)
  796. #else
  797. char *ParseArray(s, o)
  798. char *s;
  799. ObjPtr *o;
  800. #endif
  801. /*
  802.     Parses an array at s
  803.     Returns
  804.     s if the object was syntactically bad or null
  805.     the first character after the object if it was OK.
  806.     Puts in o the object if it was semantically valid
  807.         Leavs o alone if it was not
  808.     Generates a script error if syntactically or semantically invalid.
  809.     Doesn't yet do arrays of higher order than vectors by recursion
  810. */
  811. {
  812.     char *r;
  813.     r = s;
  814.  
  815.     SKIPBLANKS(r);
  816.     if (*r != '[')
  817.     {
  818.     ScriptError("This is not a valid array");
  819.     return s;
  820.     }
  821.  
  822.     ++r;
  823.     SKIPBLANKS(r);
  824.  
  825.     /*Now, it's either some subvectors or a number*/
  826.     if (*r == '[')
  827.     {
  828.     /*Subvector*/
  829.     ScriptError("Arrays of higher order than vectors are not supported yet");
  830.     return s;
  831.     }
  832.     else
  833.     {
  834.     /*Simple numerical vector.*/
  835.     real *numBuf;        /*Temporary buffer for holding real numbers*/
  836.     long bufSize;        /*Size of temporary buffer*/
  837.     long vecSize;        /*Size of the vector so far*/
  838.     char num[256];        /*Temporary number space*/
  839.  
  840.     /*Allocate some storage*/
  841.     bufSize = 1000;
  842.     vecSize = 0;
  843.     numBuf = Alloc(sizeof(real) * bufSize);
  844.     if (!numBuf)
  845.     {
  846.         OMErr();
  847.         return s;
  848.     }
  849.  
  850.     while (*r != ']')
  851.     {
  852.         SHIFTNUM(num, r);
  853.         if (1 != sscanf(num, "%g", numBuf + vecSize))
  854.         {
  855.         ScriptError("This cannot be read as a number");
  856.         Free(numBuf);
  857.         return s;
  858.         }
  859.         ++vecSize;
  860.         if (vecSize > bufSize)
  861.         {
  862.         bufSize += 1000;
  863.         numBuf = Realloc(numBuf, bufSize);
  864.         if (!numBuf)
  865.         {
  866.             OMErr();
  867.             return s;
  868.         }
  869.         }
  870.         SKIPBLANKS(r);
  871.     }
  872.     ++r;
  873.  
  874.     /*Now make it into a vector*/
  875.     *o = NewRealArray(1, vecSize);
  876.     if (!o)
  877.     {
  878.         Free(numBuf);
  879.         return s;
  880.     }
  881.     CArray2Array(*o, numBuf);
  882.     Free(numBuf);
  883.  
  884.     return r;
  885.     }
  886. }
  887.  
  888. #ifdef PROTO
  889. ObjPtr TypeCast(ObjPtr object, int type)
  890. #else
  891. ObjPtr TypeCast(object, type)
  892. ObjPtr object;
  893. int type;
  894. #endif
  895. /*Casts object to type.  Returns cast object or ERROBJ*/
  896. {
  897.     ObjPtr retVal;
  898.  
  899.     retVal = ERROBJ;
  900.  
  901.     switch (type)
  902.     {
  903.     case TC_NULL:
  904.         retVal = object;
  905.         break;
  906.     case TC_INTEGER:
  907.         if (IsInt(object))
  908.         {
  909.         retVal = object;
  910.         }
  911.         else if (IsReal(object))
  912.         {
  913.         retVal = NewInt((int) (GetReal(object)));
  914.         }
  915.         break;
  916.     }
  917.  
  918.     return retVal;
  919. }
  920.  
  921. #ifdef PROTO
  922. char *ParseObjectArg(char *s, ObjPtr *o)
  923. #else
  924. char *ParseObjectArg(s, o)
  925. char *s;
  926. ObjPtr *o;
  927. #endif
  928. /*
  929.     Parses an object at s
  930.     Returns
  931.     s if the object was syntactically bad or null
  932.     the first character after the object if it was OK.
  933.     Puts in o the object if it was semantically valid
  934.         Leavs o alone if it was not
  935.     Generates a script error if syntactically or semantically invalid.
  936. */
  937. {
  938.     char arg[256];
  939.     char *r;
  940.     int tc = TC_NULL;    /*Type cast*/
  941.  
  942.     r = s;
  943.  
  944.     /*Get to the first character*/
  945.     SKIPBLANKS(r);
  946.  
  947.     if (*r == '(')
  948.     {
  949.     /*Maybe it's a type cast*/
  950.     ++r;
  951.     SHIFTKW(arg, r);
  952.     SKIPBLANKS(r);
  953.     if (*r != ')')
  954.     {
  955.         ScriptError("Close parenthesis expected after type cast");
  956.     }
  957.     else
  958.     {
  959.         ++r;
  960.     }
  961.     if (0 == strcmp2(arg, "int"))
  962.     {
  963.         tc = TC_INTEGER;
  964.     }
  965.     else
  966.     {
  967.         ScriptError("Bad type cast");
  968.     }
  969.     SKIPBLANKS(r);
  970.     }
  971.  
  972.     /*Based on one-char lookahead, parse the argument*/
  973.     if (*r == '-' || *r == '+' || *r == '.' || isdigit(*r))
  974.     {
  975.     double val;
  976.  
  977.     /*It's a number*/
  978.     SHIFTNUM(arg, r);
  979.     if (1 == sscanf(arg, "%lg", &val))
  980.     {
  981.         *o = NewReal((real) val);
  982.     }
  983.     else
  984.     {
  985.         ScriptError("This number has bad syntax");
  986.         return s;
  987.     }
  988.     }
  989.     else if (isalpha(*r) || (*r == '\\'))
  990.     {
  991.     /*It's an object name or NULLOBJ*/
  992.     SHIFTKW(arg, r);
  993.  
  994.     if (0 == strcmp2(arg, "NULLOBJ"))
  995.     {
  996.         *o = NULLOBJ;
  997.     }
  998.     else
  999.     {
  1000.         ObjPtr list = NULLOBJ;
  1001.  
  1002.         if (*r == ':')
  1003.         {
  1004.         char arg2[256];
  1005.         WinInfoPtr window;
  1006.  
  1007.         /*Compound name, first part window*/
  1008.         ++r;
  1009.         SHIFTKW(arg2, r);
  1010.         if (strlen(arg2))
  1011.         {
  1012.             window = GetWinFromTitle(arg);
  1013.             if (window)
  1014.             {
  1015.             list = FindNamedObject((ObjPtr) window, arg2);
  1016.             }
  1017.             else
  1018.             {
  1019.             ScriptError("Cannot find a unique window by that name.");
  1020.             return s;
  1021.             }
  1022.         }
  1023.         else
  1024.         {
  1025.             ScriptError("An object name is expected after the window name.");
  1026.             return s;
  1027.         }
  1028.         }
  1029.         else if (*r == '@')
  1030.         {
  1031.         /*Class name with automatic creation*/
  1032.         int k;
  1033.         ObjPtr keyList, resultList;
  1034.         char arg2[256];
  1035.  
  1036.         ++r;
  1037.         SHIFTKW(arg2, r);
  1038.         if (!strlen(arg2))
  1039.         {
  1040.             ScriptError("An object name is expected after the object class.");
  1041.             return s;
  1042.         }
  1043.  
  1044.         for (k = 0; k < N_CLASS_IDS; ++k)
  1045.         {
  1046.             if (0 == strcmp3(arg, classNames[k]))
  1047.             {
  1048.             break;
  1049.             }
  1050.         }
  1051.  
  1052.         if (k >= N_CLASS_IDS)
  1053.         {
  1054.             ScriptError("That object class is not recognized");
  1055.             return s;
  1056.         }
  1057.  
  1058.         keyList = NewList();
  1059.         PostfixList(keyList, NewSymbol(NAME));
  1060.         PostfixList(keyList, NewString(arg2));
  1061.         PostfixList(keyList, NewSymbol(CLASSID));
  1062.         PostfixList(keyList, NewInt(k));
  1063.  
  1064.         resultList = SearchDatabase(keyList);
  1065.         if (resultList && LISTOF(resultList))
  1066.         {
  1067.             if (LISTOF(resultList) -> next)
  1068.             {
  1069.             ScriptError("Multiple objects by that name found in database.");
  1070.             }
  1071.             else
  1072.             {
  1073.             *o = LISTOF(resultList) -> thing;
  1074.             return r;
  1075.             }
  1076.         }
  1077.         else
  1078.         {
  1079.             ScriptError("No object by that name found in database.");
  1080.             return s;
  1081.         }
  1082.         }
  1083.         else
  1084.         {
  1085.         if (scriptWindow && IsValidWindow(scriptWindow))
  1086.         {
  1087.             list = FindNamedObject((ObjPtr) scriptWindow, arg);
  1088.         }
  1089.         else
  1090.         {
  1091.             ScriptError("There is no currently selected window.");
  1092.         }
  1093.         }
  1094.         if (!list || !LISTOF(list))
  1095.         {
  1096.         ScriptError("There is no object by that name.");
  1097.         }
  1098.         else if (LISTOF(list) -> next)
  1099.         {
  1100.         ScriptError("That name is not unique.");
  1101.         }
  1102.         else
  1103.         {
  1104.         *o = LISTOF(list) -> thing;
  1105.         }
  1106.     }
  1107.     }
  1108.     else if (*r == '[')
  1109.     {
  1110.     return ParseArray(r, o);
  1111.     }
  1112.     else if (*r == '"')
  1113.     {
  1114.     int k;
  1115.     /*It's a string*/
  1116.     begToken = r;
  1117.     ++r;
  1118.     k = 0;
  1119.     while (*r && *r != '"')
  1120.     {
  1121.         if (*r == '\\')
  1122.         {
  1123.         ++r;
  1124.         if (isdigit(*r))
  1125.         {
  1126.             int nDigits, value;
  1127.             value = 0;
  1128.             nDigits = 0;
  1129.             do
  1130.             {
  1131.             value *= 8;
  1132.             value += *r - '0';
  1133.             ++nDigits;
  1134.             ++r;
  1135.             } while (isdigit(*r) && nDigits < 3);
  1136.             tempStr[k++] = value;
  1137.         }
  1138.         else 
  1139.         switch (*r)
  1140.         {
  1141.             case 'n':
  1142.             case 'N':
  1143.             tempStr[k++] = '\n';
  1144.             ++r;
  1145.             break;
  1146.             case 't':
  1147.             case 'T':
  1148.             tempStr[k++] = '\t';
  1149.             ++r;
  1150.             break;
  1151.             case 'r':
  1152.             case 'R':
  1153.             tempStr[k++] = '\r';
  1154.             ++r;
  1155.             break;
  1156.             default: tempStr[k++] = *r++;
  1157.             
  1158.         }
  1159.         }
  1160.         else
  1161.         {
  1162.         tempStr[k++] = *r++;
  1163.         }
  1164.     }
  1165.     if (*r == '"') ++r;
  1166.     endToken = r;
  1167.     tempStr[k] = 0;
  1168.     *o = NewString(tempStr);
  1169.     }
  1170.     else switch(*r)
  1171.     {
  1172.     case 0:        /*End of string, null object*/
  1173.         *o = NULLOBJ;
  1174.         break;
  1175.     default:    /*Who knows?  Error*/
  1176.         ScriptError("This is an unrecognized object");
  1177.         return s;
  1178.     }
  1179.  
  1180.     *o = TypeCast(*o, tc);
  1181.  
  1182.     return r;
  1183. }  
  1184.  
  1185. char *PrintScriptString(dest, s)
  1186. char *dest, *s;
  1187. /*Prints a script string from s into dest*/
  1188. {
  1189.     *dest++ = '"';
  1190.     while (*s)
  1191.     {
  1192.         if (*s == '"')
  1193.         {
  1194.         *dest++ = '\\';
  1195.         }
  1196.         if (*s == '\n')
  1197.         {
  1198.         *dest++ = '\\';
  1199.         *dest++ = 'n';
  1200.         }
  1201.         else if (*s == '\t')
  1202.         {
  1203.         *dest++ = '\\';
  1204.         *dest++ = 't';
  1205.         }
  1206.         else if (*s == '\r')
  1207.         {
  1208.         *dest++ = '\\';
  1209.         *dest++ = 'r';
  1210.         }
  1211.         else if (*s < ' ')
  1212.         {
  1213.         *dest++ = '\\';
  1214.         sprintf(tempStr, "%3o", *s);
  1215.         *dest++ = tempStr[0];
  1216.         *dest++ = tempStr[1];
  1217.         *dest++ = tempStr[2];
  1218.         }
  1219.         else
  1220.         {
  1221.         *dest++ = *s;
  1222.         }
  1223.         ++s;
  1224.     }
  1225.     *dest++ = '"';
  1226.     *dest = 0;
  1227.     return dest;
  1228. }
  1229.  
  1230. char *PrintScriptObject(s, object)
  1231. char *s;
  1232. ObjPtr object;
  1233. /*Prints object into s as for inclusion into a script.  Returns a pointer
  1234.   to the null afterward*/
  1235. {
  1236.     char *retVal;
  1237.     retVal = s;
  1238.     if (object == 0)
  1239.     {
  1240.     sprintf(retVal, "NULLOBJ");
  1241.     while (*retVal) ++retVal;
  1242.     }
  1243.     else if (IsReal(object))
  1244.     {
  1245.     /*Real number*/
  1246.     sprintf(retVal, "%g", (float) GetReal(object));
  1247.     while (*retVal) ++retVal;
  1248.     }
  1249.     else if (IsInt(object))
  1250.     {
  1251.     sprintf(retVal, "%ld", (long) GetInt(object));
  1252.     while (*retVal) ++retVal;
  1253.     }
  1254.     else if (IsRealArray(object) && RANK(object) == 1)
  1255.     {
  1256.     /*Vector*/
  1257.     int k;
  1258.     real *meat;
  1259.  
  1260.     *retVal++ = '[';
  1261.     meat = ArrayMeat(object);
  1262.     for (k = 0; k < DIMS(object)[0]; ++k)
  1263.     {
  1264.         sprintf(retVal, "%g", *meat++);
  1265.         while (*retVal) ++retVal;
  1266.         if (k < DIMS(object)[0] - 1) *retVal++ = ' ';
  1267.     }
  1268.     *retVal++ = ']';
  1269.     }
  1270.     else if (IsString(object))
  1271.     {
  1272.     /*String*/
  1273.     retVal = PrintScriptString(retVal, GetString(object));
  1274.     }
  1275.     else
  1276.     {
  1277.     MakeObjectName(retVal, object);
  1278.     while (*retVal) ++retVal;
  1279.     }
  1280.     *retVal = 0;
  1281.     return retVal;
  1282. }
  1283.  
  1284. int FindCommandInStack(command)
  1285. int command;
  1286. /*Finds the topmost command command in the stack.  Returns it's index or -1
  1287.   if not found.*/
  1288. {
  1289.     int k;
  1290.     for (k = nextStackElement - 1; k >= 0; --k)
  1291.     {
  1292.     if (commandStack[k] . command == command)
  1293.     {
  1294.         break;
  1295.     }
  1296.     }
  1297.     return k;
  1298. }
  1299.  
  1300. Bool BeginCommand(args)
  1301. char *args;
  1302. /*Begins a begin-end block with command in args.*/
  1303. {
  1304.     char cmdNum;
  1305.     char arg[256];
  1306.  
  1307.     if (nextStackElement >= MAXSTACKDEPTH)
  1308.     {
  1309.     ScriptError("There are too many nested begin-end blocks.");
  1310.     return true;
  1311.     }
  1312.  
  1313.     SHIFTKW(arg, args);
  1314.  
  1315.     if (strlen(arg))
  1316.     {
  1317.     cmdNum = ParseKeyword(arg, keywords, NKEYWORDS);
  1318.     if (cmdNum == -1)
  1319.     {
  1320.         ScriptError("This command is unknown.");
  1321.         return true;
  1322.     }
  1323.     else if (cmdNum == -2)
  1324.     {
  1325.         ScriptError("This command is ambiguous.");
  1326.         return true;
  1327.     }
  1328.     }
  1329.     else
  1330.     {
  1331.     /*It's an anonymous block*/
  1332.     cmdNum = KWBEGIN;
  1333.     }
  1334.     commandStack[nextStackElement] . command = cmdNum;
  1335.     commandStack[nextStackElement] . object = NULLOBJ;
  1336.     switch (cmdNum)
  1337.     {
  1338.     case KWBEGIN:
  1339.         Log("begin\n");
  1340.         break;
  1341.     case KWRECORDING:
  1342.         Log("begin recording\n");
  1343.         if (FindCommandInStack(KWRECORDING) >= 0)
  1344.         {
  1345.         ScriptError("The begin recording command cannot be nested.");
  1346.         return true;
  1347.         }
  1348.         else
  1349.         {
  1350.         real nSeconds;
  1351.         
  1352.         SHIFTNUM(arg, args);
  1353.         if (1 != sscanf(arg, "%g", &nSeconds))
  1354.         {
  1355.             ScriptError("A maximum time in seconds is expected here.");
  1356.             return true;
  1357.         }
  1358.         if (nSeconds < 0.0) nSeconds = -nSeconds;
  1359.         if (AdjustToVisWindows(curRecorder))
  1360.         if (ConnectRecorder())
  1361.         {
  1362.             int nFrames;
  1363.             nFrames = (int) (nSeconds * 30.0);
  1364.  
  1365.             PushNonVisWindows();
  1366.             if (!PrepareToRecord(nFrames))
  1367.             {
  1368.             ScriptError("There is a problem recording that many frames.");
  1369.             return true;
  1370.             }
  1371.         }
  1372.         else
  1373.         {
  1374.             ScriptError("Could not connect to the recorder.");
  1375.             return true;
  1376.         }
  1377.         else
  1378.         {
  1379.             ScriptError("There are no visualization windows to record.");
  1380.             return true;
  1381.         }
  1382.         }
  1383.         break;
  1384.     case KWSETUP:
  1385.         Log("begin setup\n");
  1386.         settingUp = true;
  1387.         break;
  1388.     case KWSNAPSHOT:
  1389.         /*Beginning of an object snapshot*/
  1390.         {
  1391.         ObjPtr value;
  1392.         value = ERROBJ;
  1393.         SKIPBLANKS(args);
  1394.         Log("begin snapshot ");
  1395.         Log(args);
  1396.         Log("\n");
  1397.         args = ParseObjectArg(args, &value);
  1398.         if (value != ERROBJ)
  1399.         {
  1400.             commandStack[nextStackElement] . object = value;
  1401.         }
  1402.         else
  1403.         {
  1404.             ScriptError("An object for the snapshot is expected here");
  1405.             commandStack[nextStackElement] . object = NULLOBJ;
  1406.         }
  1407.         }
  1408.         break;
  1409.     case KWSCRIPT:
  1410.         /*Sub script, do nothing*/
  1411.         break;
  1412.     default:
  1413.         ScriptError("This command may not start a begin-end block");
  1414.         return true;
  1415.     }
  1416.     ++nextStackElement;
  1417.     return true;
  1418. }
  1419.  
  1420. Bool EndCommand(args)
  1421. char *args;
  1422. /*Ends the top command on the stack, or up to command in args*/
  1423. {
  1424.     char arg[256];
  1425.     if (!nextStackElement)
  1426.     {
  1427.     ScriptError("There are too many ends and not enough begins.");
  1428.     return true;
  1429.     }
  1430.  
  1431.     SHIFTKW(arg, args);
  1432.     if (strlen(arg))
  1433.     {
  1434.     int cmdNum, cmdWhere;
  1435.     cmdNum = ParseKeyword(arg, keywords, NKEYWORDS);
  1436.     cmdWhere = FindCommandInStack(cmdNum);
  1437.     if (cmdWhere < 0)
  1438.     {
  1439.         ScriptError("There is no such block in force.");
  1440.         return true;
  1441.     }
  1442.     else
  1443.     {
  1444.         do
  1445.         {
  1446.         EndCommand("");
  1447.         } while (commandStack[nextStackElement] . command != cmdNum);
  1448.     }
  1449.     }
  1450.     else
  1451.     {
  1452.     /*End the top command*/
  1453.     --nextStackElement;
  1454.     switch(commandStack[nextStackElement] . command)
  1455.     {
  1456.         case KWBEGIN:
  1457.         Log("end\n");
  1458.         break;
  1459.         case KWRECORDING:
  1460.         Log("end recording\n");
  1461.         StopRecording();
  1462.         DisconnectRecorder();
  1463.         break;
  1464.         case KWSNAPSHOT:
  1465.         Log("end snapshot\n");
  1466.         if (commandStack[nextStackElement] . object)
  1467.         {
  1468.             ImInvalid(commandStack[nextStackElement] . object);
  1469.         }
  1470.         break;
  1471.         case KWSETUP:
  1472.         Log("end setup\n");
  1473.         settingUp = false;
  1474.         break;
  1475.         case KWSCRIPT:
  1476.         /*Script, do nothing.*/
  1477.         break;
  1478.     }
  1479.     }
  1480.     return true;
  1481. }
  1482.  
  1483. Bool DoSetCommand(kwn, args)
  1484. int kwn;
  1485. char *args;
  1486. /*Does a set command*/
  1487. {
  1488.     char arg[256];
  1489.  
  1490.     switch(kwn)
  1491.     {
  1492.     case KWVARIABLE:
  1493.         /*Set a variable within a snapshot*/
  1494.         {
  1495.         int element;
  1496.  
  1497.         /*DIKEO put in type checking*/
  1498.         element = FindCommandInStack(KWSNAPSHOT);
  1499.         if (element >= 0)
  1500.         {
  1501.             /*Do a setvar, just like it says*/
  1502.             NameTyp internalID;
  1503.             ObjPtr value;
  1504.  
  1505.             SHIFTKW(arg, args);
  1506.             internalID = GetInternalID(arg);
  1507.             
  1508.             value = ERROBJ;
  1509.             args = ParseObjectArg(args, &value);
  1510.             if (value != ERROBJ)
  1511.             {
  1512.             if (commandStack[element] . object)
  1513.             {
  1514.                 SetVar(commandStack[element] . object, internalID, value);
  1515.                 LogVariable(commandStack[element] . object, internalID);
  1516.             }
  1517.             }
  1518.             else
  1519.             {
  1520.             ScriptError("A valid value is expected here");
  1521.             }
  1522.         }
  1523.         else
  1524.         {
  1525.             ScriptError("A set variable command can only occur within a snapshot");
  1526.         }
  1527.         }
  1528.         break;
  1529.     case KWRECORDER:
  1530.         {
  1531.         ObjPtr object;
  1532.         if (FindCommandInStack(KWRECORDING) >= 0)
  1533.         {
  1534.             ScriptError("You can't set the recorder while recording");
  1535.             break;
  1536.         }
  1537.         object = ERROBJ;
  1538.         args = ParseObjectArg(args, &object);
  1539.         if (object != ERROBJ)
  1540.         {
  1541.             if (IsString(object))
  1542.             {
  1543.             if (!SetRecorder(GetString(object)))
  1544.             {
  1545.                 ScriptError("This recorder does not exist");
  1546.             }
  1547.             }
  1548.             else
  1549.             {
  1550.             ScriptError("A quoted name of a recorder is expected here");
  1551.             }
  1552.         }
  1553.         }
  1554.         break;
  1555.     case KWVALUE:
  1556.         /*Set the value of a control*/
  1557.         {
  1558.         ObjPtr object, value;
  1559.         object = ERROBJ;
  1560.  
  1561.         args = ParseObjectArg(args, &object);
  1562.         if (object != ERROBJ)
  1563.         {
  1564.             if (object && IsObject(object))
  1565.             {
  1566.             value = ERROBJ;
  1567.             args = ParseObjectArg(args, &value);
  1568.             if (value != ERROBJ)
  1569.             {
  1570.                 SetValue(object, value);
  1571.             }
  1572.             else
  1573.             {
  1574.                 ScriptError("A valid value is expected here");
  1575.             }
  1576.             }
  1577.             else
  1578.             {
  1579.             ScriptError("An object name is expected here");
  1580.             }
  1581.         }
  1582.         }
  1583.         break;
  1584.     case KWROTATION:
  1585.         {
  1586.         ObjPtr rotation, axis;
  1587.         rotation = ERROBJ;
  1588.  
  1589.         args = ParseObjectArg(args, &rotation);
  1590.         if (rotation != ERROBJ)
  1591.         {
  1592.             if (rotation && IsReal(rotation))
  1593.             {
  1594.             axis = ERROBJ;
  1595.             args = ParseObjectArg(args, &axis);
  1596.             if (axis != ERROBJ && axis &&
  1597.                 IsRealArray(axis) && RANK(axis) == 1 && DIMS(axis)[0] == 3)
  1598.             {
  1599.                 real *elements;
  1600.                 real degrees;
  1601.                 elements = ELEMENTS(axis);
  1602.                 degrees = GetReal(rotation);
  1603.                 SetRotationMotor(degrees * M_PI / 180.0, elements[0], elements[1], elements[2]);
  1604.             }
  1605.             else
  1606.             {
  1607.                 ScriptError("A rotation axis is expected here");
  1608.             }
  1609.             }
  1610.             else
  1611.             {
  1612.             ScriptError("A rotation speed is expected here");
  1613.             }
  1614.         }
  1615.         }
  1616.         break;
  1617.     case KWFUNCTIONBOX:
  1618.         {
  1619.         ObjPtr object, functionBox;
  1620.         object = ERROBJ;
  1621.  
  1622.         args = ParseObjectArg(args, &object);
  1623.         if (object != ERROBJ)
  1624.         {
  1625.             if (IsObject(object))
  1626.             {
  1627.             functionBox = ERROBJ;
  1628.             args = ParseObjectArg(args, &functionBox);
  1629.             if (functionBox != ERROBJ)
  1630.             {
  1631.                 SetFunctionBox(object, functionBox);
  1632.                 InhibitLogging(true);
  1633.                 ImposeColorFunction(object);
  1634.                 ForAllVisWindows(ImInvalid);
  1635.                 InhibitLogging(false);
  1636.             }
  1637.             else
  1638.             {
  1639.                 ScriptError("A valid function box is expected here");
  1640.             }
  1641.             }
  1642.             else
  1643.             {
  1644.             ScriptError("An object name is expected here");
  1645.             }
  1646.         }
  1647.         }
  1648.         break;
  1649.     case KWCOLOR:
  1650.         {
  1651.         ObjPtr object;
  1652.         int which, r, g, b;
  1653.  
  1654.         object = ERROBJ;
  1655.  
  1656.         args = ParseObjectArg(args, &object);
  1657.         if (object != ERROBJ)
  1658.         {
  1659.             if (IsObject(object))
  1660.             {
  1661.             if (4 == sscanf(args, " %d %d %d %d \n", &which, &r, &g, &b))
  1662.             {
  1663.                 SetColorBarColor(object, which, r, g, b);
  1664.             }
  1665.             else
  1666.             {
  1667.                 ScriptError("A color number and components are expected here");
  1668.             }
  1669.             }
  1670.             else
  1671.             {
  1672.             ScriptError("An object name is expected here");
  1673.             }
  1674.         }
  1675.         }
  1676.         break;
  1677.     case KWLOCATION:
  1678.         {
  1679.         ObjPtr object, value;
  1680.         object = ERROBJ;
  1681.         args = ParseObjectArg(args, &object);
  1682.         if (object != ERROBJ)
  1683.         {
  1684.             if (IsObject(object))
  1685.             {
  1686.             real location[3];
  1687.             if (3 == sscanf(args, " [%g %g %g]", 
  1688.                 &(location[0]),
  1689.                 &(location[1]),
  1690.                 &(location[2])))
  1691.             {
  1692.                 ObjPtr var;
  1693.                 var = NewRealArray(1, 3L);
  1694.                 CArray2Array(var, location);
  1695.                 SetVar(object, LOCATION, var);
  1696.                 ImInvalid(object);
  1697.                 {
  1698.                 char cmd[300];
  1699.                 char *s;
  1700.                 sprintf(cmd, "set location ");
  1701.  
  1702.                 s = &(cmd[0]);
  1703.                 while (*s) ++s;
  1704.                 MakeObjectName(s, object);
  1705.                 while (*s) ++s;
  1706.                 sprintf(s, " [%g %g %g]\n",
  1707.                     location[0],
  1708.                     location[1],
  1709.                     location[2]);
  1710.                 Log(cmd);
  1711.                 }
  1712.             }
  1713.             else
  1714.             {
  1715.                 ScriptError("A vector location is expected here");
  1716.             }
  1717.             }
  1718.             else
  1719.             {
  1720.             ScriptError("An object name is expected here");
  1721.             }
  1722.         }
  1723.         }
  1724.         break;
  1725.     case KWBOUNDS:
  1726.         {
  1727.         ObjPtr object;
  1728.         ObjPtr bounds;
  1729.         char *oldArgs;
  1730.         object = ERROBJ;
  1731.         oldArgs = args;
  1732.         args = ParseObjectArg(args, &object);
  1733.         if (object != ERROBJ)
  1734.         {
  1735.             if (IsObject(object))
  1736.             {
  1737.             bounds = ERROBJ;
  1738.             args = ParseObjectArg(args, &bounds);
  1739.             if (bounds != ERROBJ)
  1740.             {
  1741.                 if (IsRealArray(bounds) && RANK(bounds) == 1)
  1742.                 {
  1743.                 ObjPtr testBounds;
  1744.                 testBounds = GetVar(object, BOUNDS);
  1745.                 if (!testBounds ||
  1746.                     (IsRealArray(testBounds) && 
  1747.                      RANK(testBounds) == 1 &&
  1748.                      DIMS(testBounds)[0] == DIMS(bounds)[0]))
  1749.                 {
  1750.                     {
  1751.                     char cmd[256];
  1752.                     sprintf(cmd, "set bounds %s\n", oldArgs);
  1753.                     Log(cmd);
  1754.                     }
  1755.                         SetVar(object, BOUNDS, bounds);
  1756.                     ImInvalid(object);
  1757.                 }
  1758.                 else
  1759.                 {
  1760.                     ScriptError("These bounds are of wrong size for the object");
  1761.                 }
  1762.                 }
  1763.                 else
  1764.                 {
  1765.                 ScriptError("A vector is expected here");
  1766.                 }
  1767.             }
  1768.             }
  1769.             else
  1770.             {
  1771.             ScriptError("An object name is expected here");
  1772.             }
  1773.         }
  1774.         }
  1775.         break;
  1776.     case KWENDPOINTS:
  1777.         {
  1778.         ObjPtr object;
  1779.         int x1, y1, x2, y2;
  1780.         char *oldArgs;
  1781.         object = ERROBJ;
  1782.         oldArgs = args;
  1783.         args = ParseObjectArg(args, &object);
  1784.         if (object != ERROBJ)
  1785.         {
  1786.             if (IsObject(object))
  1787.             {
  1788.             if (4 == sscanf(args, " %d %d %d %d", &x1, &y1, &x2, &y2))
  1789.             {
  1790.                 SetEndpoints(object, x1, y1, x2, y2);
  1791.                 ImInvalid(object);
  1792.             }
  1793.             else
  1794.             {
  1795.                 ScriptError("Four endpoint coordinates are expected here");
  1796.             }
  1797.             }
  1798.             else
  1799.             {
  1800.             ScriptError("An object name is expected here");
  1801.             }
  1802.         }
  1803.         }
  1804.         break;
  1805.     case KWSCREEN:
  1806.         {
  1807.         /*Set the size of the recording screen*/
  1808.         int x, y;
  1809.         if (2 != sscanf(args, " %d %d", &x, &y))
  1810.         {
  1811.             ScriptError("A width and height of the recording screen is expected here");
  1812.             break;
  1813.         }
  1814.         SetScreenSize(x, y);
  1815.         }
  1816.         break;
  1817.     case KWFPS:
  1818.         {
  1819.         /*Set the frames per second*/
  1820.         real fps;
  1821.         if (1 != sscanf(args, " %g", &fps))
  1822.         {
  1823.             ScriptError("A number of frames per second is expected here");
  1824.             break;
  1825.         }
  1826.         SetFPS(fps);
  1827.         }
  1828.         break;
  1829.     default:
  1830.         ScriptError("This is not a paramater that can be set");
  1831.         break;
  1832.     }
  1833.     return true;
  1834. }
  1835.  
  1836.  
  1837. Bool DoSaveCommand(kwn, args)
  1838. int kwn;
  1839. char *args;
  1840. /*Does a save command*/
  1841. {
  1842.     char arg[256];
  1843.  
  1844.     switch(kwn)
  1845.     {
  1846.     case KWCONTROLS:
  1847.         DoSaveObject();
  1848.         break;
  1849.     case KWSCREEN:
  1850.         SaveScreen(scriptWindow, F_OPTIONDOWN);
  1851.         break;
  1852.     case KWWINDOW:
  1853.         SaveScreen(scriptWindow, 0);
  1854.         break;
  1855.     default:
  1856.         ScriptError("This is not something that can be saved");
  1857.         return;
  1858.         break;
  1859.     }
  1860.     return true;
  1861. }
  1862.  
  1863. Bool DoShowHideCommand(showp, kwn, args)
  1864. Bool showp;
  1865. int kwn;
  1866. char *args;
  1867. /*Does a show or hide command, showp is true iff it's show*/
  1868. {
  1869.     char arg[256];
  1870.  
  1871.     switch(kwn)
  1872.     {
  1873.     case KWPANEL:
  1874.         if (showp)
  1875.         {
  1876.         DoShowPanel();
  1877.         }
  1878.         else
  1879.         {
  1880.         DoHidePanel();
  1881.         }
  1882.         break;
  1883.     case KWDATASETS:
  1884.         if (showp)
  1885.         {
  1886.         PopDatasetsWindow();
  1887.         }
  1888.         else
  1889.         {
  1890.         ScriptError("You can't hide the datasets window this way.  Close the window instead");
  1891.         }
  1892.         break;
  1893.     case KWFILEREADERS:
  1894.         if (showp)
  1895.         {
  1896.         PopFileReadersWindow();
  1897.         }
  1898.         else
  1899.         {
  1900.         ScriptError("You can't hide the file readers window this way.  Close the window instead");
  1901.         }
  1902.         break;
  1903.     case KWRECORDERS:
  1904.         if (showp)
  1905.         {
  1906.         PopRecorderDriversWindow();
  1907.         }
  1908.         else
  1909.         {
  1910.         ScriptError("You can't hide the recorder drivers window this way.  Close the window instead");
  1911.         }
  1912.         break;
  1913.     case KWFILESWINDOW:
  1914.         if (showp)
  1915.         {
  1916.         DoNewFileWindow();
  1917.         }
  1918.         else
  1919.         {
  1920.         ScriptError("You can't hide the file window this way.  Close the window instead");
  1921.         }
  1922.         break;
  1923.     case KWFRAME:
  1924.         if (showp)
  1925.         {
  1926.         DoShowFrame();
  1927.         }
  1928.         else
  1929.         {
  1930.         DoHideFrame();
  1931.         }
  1932.         break;
  1933.     case KWFRONT:
  1934.         if (showp)
  1935.         {
  1936.         DoShowFrontPanelControls();
  1937.         }
  1938.         else
  1939.         {
  1940.         ScriptError("You can't hide the front panel controls this way.  Close the window instead");
  1941.         }
  1942.         break;
  1943.     case KWBACK:
  1944.         if (showp)
  1945.         {
  1946.         DoShowBackPanelControls();
  1947.         }
  1948.         else
  1949.         {
  1950.         ScriptError("You can't hide the back panel controls this way.  Close the window instead");
  1951.         }
  1952.         break;
  1953.     case KWSPACE:
  1954.         if (showp)
  1955.         {
  1956.         DoShowSpaceControls();
  1957.         }
  1958.         else
  1959.         {
  1960.         ScriptError("You can't hide the space controls this way.  Close the window instead");
  1961.         }
  1962.         break;
  1963.  
  1964.     default:
  1965.         ScriptError("This keyword is not a settable parameter");
  1966.         break;
  1967.     }
  1968.     return true;
  1969. }
  1970.  
  1971. #ifdef PROTO
  1972. void ShowScriptControlPanels(Bool whether)
  1973. #else
  1974. void ShowScriptControlPanels(whether)
  1975. Bool whether;
  1976. #endif
  1977. /*Turns subsequent showing of control panels within a script on or off*/
  1978. {
  1979.     showControlPanels = whether;
  1980.     Log(whether ? "turn show controls on\n" : "turn show controls off");
  1981. }
  1982.  
  1983. void VersionCommand(args)
  1984. char *args;
  1985. /*Does a version command*/
  1986. {
  1987.     char arg[256];
  1988.     float scianVersion, scriptVersion;
  1989.     SHIFTNUM(arg, args);
  1990.  
  1991.     if (1 != sscanf(arg, "%g", &scriptVersion))
  1992.     {
  1993.     ScriptError("A number is expected here");
  1994.     return;
  1995.     }
  1996.         
  1997.     if (1 != sscanf(SCIANVERSION, "Version %g", &scianVersion))
  1998.     {
  1999.     ReportError("VersionCommand", "Internal error: cannot parse SciAn version");
  2000.     return;
  2001.     }
  2002.  
  2003.     if (scianVersion < scriptVersion)
  2004.     {
  2005.     ScriptError("The script is newer than this version of SciAn");
  2006.     if (abortScriptP)
  2007.     {
  2008.         abortScript = true;
  2009.     }
  2010.     }
  2011.     if (scianVersion > scriptVersion)
  2012.     {
  2013. #if 0
  2014.     ScriptError("The script is older than this version of SciAn");
  2015.     if (abortScriptP)
  2016.     {
  2017.         abortScript = true;
  2018.     }
  2019. #endif
  2020.     }
  2021. }
  2022.  
  2023. #ifdef PROTO
  2024. void SelectCommand(char *args, Bool selectP)
  2025. #else
  2026. void SelectCommand(args, selectP)
  2027. char *args;
  2028. Bool selectP;
  2029. #endif
  2030. /*Does select or deselect depending on selectP*/
  2031. {
  2032.     ObjPtr object;
  2033.     object = ERROBJ;
  2034.     args = ParseObjectArg(args, &object);
  2035.      if (object != ERROBJ)
  2036.     {
  2037.         if (IsObject(object))
  2038.         {
  2039.         Select(object, selectP);
  2040.         }
  2041.         else
  2042.         {
  2043.         ScriptError("An object name is expected here");
  2044.         }
  2045.     }
  2046. }
  2047.  
  2048. #ifdef PROTO
  2049. void TurnCommand(char *args)
  2050. #else
  2051. void TurnCommand(args)
  2052. char *args;
  2053. #endif
  2054. /*Does turn show controls on/off.  Normal turn on/off done by obj
  2055.   functions.*/
  2056.     {
  2057.     char arg[256];
  2058.     int kwn;
  2059.     SHIFTKW(arg, args);
  2060.     kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2061.     if (kwn == KWSHOW)
  2062.     {
  2063.         SHIFTKW(arg, args);
  2064.         kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2065.         if (kwn == KWCONTROLS)
  2066.         {
  2067.         SHIFTKW(arg, args);
  2068.         kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2069.         
  2070.         if (kwn == KWON)
  2071.         {
  2072.             ShowScriptControlPanels(true);
  2073.         }
  2074.         else if (kwn == KWOFF)
  2075.         {
  2076.             ShowScriptControlPanels(false);
  2077.         }
  2078.         }
  2079.         else
  2080.         {
  2081.         ScriptError("'Controls' is expected here");
  2082.         }
  2083.     }
  2084.     else
  2085.     {
  2086.         ScriptError("Either 'on' or 'off' is expected here");
  2087.     }
  2088.     }
  2089.  
  2090.  
  2091. Bool DoScriptCommand(kwn, args)
  2092. int kwn;
  2093. char *args;
  2094. /*Does command kwn with args*/
  2095. {
  2096.     char arg[256];
  2097.  
  2098.     switch(kwn)
  2099.     {
  2100.     case KWVERSION:
  2101.         VersionCommand(args);
  2102.         break;
  2103.     case KWTIME:
  2104.         break;
  2105.     case KWDELETE:
  2106.         DoDelete();
  2107.         break;
  2108.     case KWTURN:
  2109.         /*Turn show controls on/off.  Turn on/off handled by objfunctions*/
  2110.         TurnCommand(args);
  2111.         break;
  2112.     case KWSELECT:
  2113.         SelectCommand(args, true);
  2114.         break;
  2115.     case KWDESELECT:
  2116.         SelectCommand(args, false);
  2117.         break;
  2118.     case KWSELECTALL:
  2119.         DoSelectAllIcons();
  2120.         break;
  2121.     case KWDESELECTALL:
  2122.         DeselectAll();
  2123.         break;
  2124.     case KWANNOTATION:
  2125.     case KWTIMEREADOUT:
  2126.     case KWRECTANGLE:
  2127.         {
  2128.         char name[256];
  2129.         ObjPtr bounds;
  2130.         SHIFTKW(name, args);
  2131.         if (strlen(name))
  2132.         {
  2133.             bounds = ERROBJ;
  2134.             args = ParseObjectArg(args, &bounds);
  2135.             if (bounds != ERROBJ)
  2136.             {
  2137.             if (IsRealArray(bounds) && RANK(bounds) == 1 &&
  2138.                 DIMS(bounds)[0] == 4)
  2139.             {
  2140.                 switch(kwn)
  2141.                 {
  2142.                 case KWANNOTATION:
  2143.                     AddAnnotation(name, ArrayMeat(bounds));
  2144.                     break;
  2145.                 case KWTIMEREADOUT:
  2146.                     AddTimeReadout(name, ArrayMeat(bounds));
  2147.                     break;
  2148.                 case KWRECTANGLE:
  2149.                     AddRectangle(name, ArrayMeat(bounds));
  2150.                     break;
  2151.                 }
  2152.             }
  2153.             else
  2154.             {
  2155.                 ScriptError("A 4-vector is expected here");
  2156.             }
  2157.             }
  2158.         }
  2159.         else
  2160.         {
  2161.             ScriptError("A name is expected here");
  2162.         }
  2163.         }
  2164.         break;
  2165.     case KWLINE:
  2166.         {
  2167.         char name[256];
  2168.         int x1, y1, x2, y2;
  2169.         SHIFTKW(name, args);
  2170.         if (strlen(name))
  2171.         {
  2172.             if (4 == sscanf(args, " %d %d %d %d", &x1, &y1, &x2, &y2))
  2173.             {
  2174.             AddLine(name, x1, y1, x2, y2);
  2175.             }
  2176.             else
  2177.             {
  2178.             ScriptError("Four endpoint coordinates are expected here");
  2179.             }
  2180.         }
  2181.         else
  2182.         {
  2183.             ScriptError("A name is expected here");
  2184.         }
  2185.         }
  2186.         break;
  2187.     case KWSET:            /*Set something or other*/
  2188.         {
  2189.         int k;
  2190.         SHIFTKW(arg, args);
  2191.         /*Find out what to set*/
  2192.         kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2193.         if (kwn == -1)
  2194.         {
  2195.             ScriptError("This parameter is unknown.");
  2196.             break;
  2197.         }
  2198.         else if (kwn == -2)
  2199.         {
  2200.             ScriptError("This parameter is ambiguous.");
  2201.             break;
  2202.         }
  2203.         else
  2204.         {
  2205.             return DoSetCommand(kwn, args);
  2206.         }
  2207.         }
  2208.         break;
  2209.     case KWSAVE:            /*Save something or other*/
  2210.         {
  2211.         int k;
  2212.         SHIFTKW(arg, args);
  2213.         /*Find out what to set*/
  2214.         kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2215.         if (kwn == -1)
  2216.         {
  2217.             ScriptError("This parameter is unknown.");
  2218.             break;
  2219.         }
  2220.         else if (kwn == -2)
  2221.         {
  2222.             ScriptError("This parameter is ambiguous.");
  2223.             break;
  2224.         }
  2225.         else
  2226.         {
  2227.             return DoSaveCommand(kwn, args);
  2228.         }
  2229.         }
  2230.         break;
  2231.     case KWSHOW:            /*Show something or other*/
  2232.         {
  2233.         int k;
  2234.         SHIFTKW(arg, args);
  2235.         /*Find out what to set*/
  2236.         kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2237.         if (kwn == -1)
  2238.         {
  2239.             ScriptError("This parameter is unknown.");
  2240.             break;
  2241.         }
  2242.         else if (kwn == -2)
  2243.         {
  2244.             ScriptError("This parameter is ambiguous.");
  2245.             break;
  2246.         }
  2247.         else
  2248.         {
  2249.             return DoShowHideCommand(true, kwn, args);
  2250.         }
  2251.         }
  2252.         break;
  2253.     case KWHIDE:            /*Hide something or other*/
  2254.         {
  2255.         int k;
  2256.         SHIFTKW(arg, args);
  2257.         /*Find out what to set*/
  2258.         kwn = ParseKeyword(arg, keywords, NKEYWORDS);
  2259.         if (kwn == -1)
  2260.         {
  2261.             ScriptError("This parameter is unknown.");
  2262.             break;
  2263.         }
  2264.         else if (kwn == -2)
  2265.         {
  2266.             ScriptError("This parameter is ambiguous.");
  2267.             break;
  2268.         }
  2269.         else
  2270.         {
  2271.             return DoShowHideCommand(false, kwn, args);
  2272.         }
  2273.         }
  2274.         break;
  2275.     case KWDROP:
  2276.         {
  2277.         int dropX, dropY;
  2278.         
  2279.         SHIFTNUM(arg, args);
  2280.         if (1 != sscanf(arg, "%d", &dropX))
  2281.         {
  2282.             ScriptError("A number is expected here");
  2283.             break;
  2284.         }
  2285.  
  2286.         SHIFTNUM(arg, args);
  2287.         if (1 != sscanf(arg, "%d", &dropY))
  2288.         {
  2289.             ScriptError("A number is expected here");
  2290.             break;
  2291.         }
  2292.  
  2293.         if (scriptWindow && dragBuffer)
  2294.         {
  2295.             FuncTyp method;
  2296.             /*Drop*/
  2297.             method = GetMethod((ObjPtr) scriptWindow, DROPOBJECTS);
  2298.             if (method)
  2299.             {
  2300.             iconXOff = 0;
  2301.             iconYOff = 0;
  2302.             {
  2303.                 char cmd[256];
  2304.                 sprintf(cmd, "drop %d %d\n", dropX, dropY);
  2305.                 Log(cmd);
  2306.                 InhibitLogging(true);
  2307.             }
  2308.             (*method)(scriptWindow, dragBuffer, dropX, dropY);
  2309.             DeleteThing(dragBuffer);
  2310.             dragBuffer = NULLOBJ;
  2311.                 InhibitLogging(false);
  2312.             }
  2313.         }
  2314.         else
  2315.         {
  2316.             ScriptError("There is no selected window");
  2317.         }
  2318.         }
  2319.         break;
  2320.     case KWVIDEOSCREEN:
  2321.         DoVideoScreen();
  2322.         break;
  2323.     case KWFULLSCREEN:
  2324.         DoMaxScreen();
  2325.         break;
  2326.     case KWTILE:
  2327.         {
  2328.         int width, height;
  2329.  
  2330.         SHIFTNUM(arg, args);
  2331.         if (1 != sscanf(arg, "%d", &width))
  2332.         {
  2333.             ScriptError("A width is expected here");
  2334.             break;
  2335.         }
  2336.  
  2337.         SHIFTNUM(arg, args);
  2338.         if (1 != sscanf(arg, "%d", &height))
  2339.         {
  2340.             ScriptError("A height is expected here");
  2341.             break;
  2342.         }
  2343.  
  2344.         Tile(width, height);
  2345.         }
  2346.         break;
  2347.     case KWLOCATE:
  2348.         {
  2349.         int l, r, b, t;
  2350.         if (4 != sscanf(args, " %d %d %d %d", &l, &r, &b, &t))
  2351.         {
  2352.             ScriptError("The bounds of the window are expected here.");
  2353.             return true;
  2354.         }
  2355.         LocateWindow(l, r, b, t);
  2356.         }
  2357.         break;
  2358.     case KWEYEPOSN:
  2359.         {
  2360.         if (scriptWindow)
  2361.         {
  2362.             ObjPtr array, observer /*, observers*/;
  2363.             array = ERROBJ;
  2364.     
  2365.             args = ParseObjectArg(args, &array);
  2366.             if (array != ERROBJ)
  2367.             {
  2368.             observer = FindObserver(scriptWindow);
  2369.             if (!observer) break;
  2370.  
  2371.             if (IsArray(array) && RANK(array) == 1 && DIMS(array)[0] == 3)
  2372.             {
  2373.                 real *p;
  2374.                 SetVar(observer, LOCATION, array);
  2375.                 ImInvalid(observer);
  2376.                 p = ELEMENTS(array);
  2377.                 {
  2378.                 char cmd[256];
  2379.                 sprintf(cmd, "eyeposn [%g %g %g]\n",
  2380.                     p[0], p[1], p[2]);
  2381.                 Log(cmd);
  2382.                 }
  2383.             }
  2384.             else
  2385.             {
  2386.                 ScriptError("A 3-vector is expected here");
  2387.             }
  2388.             }
  2389.          }
  2390.         }
  2391.         break;
  2392.     case KWROLL:
  2393.         {
  2394.         float value;
  2395.         SHIFTKW(arg, args);
  2396.         if (strlen(arg) && 1 == sscanf(arg, " %g", &value))
  2397.         {
  2398.             if (scriptWindow)
  2399.             {
  2400.             ObjPtr observer /*, observers*/;
  2401.             observer = FindObserver(scriptWindow);
  2402.             if (!observer) break;
  2403.  
  2404.             SetVar(observer, ROLL, NewReal(value));
  2405.             }
  2406.         }
  2407.         else
  2408.         {
  2409.             ScriptError("An amount to roll is expected here.");
  2410.         }
  2411.         }
  2412.         break;
  2413.     case KWPITCH:
  2414.         {
  2415.         float value;
  2416.         SHIFTKW(arg, args);
  2417.         if (strlen(arg) && 1 == sscanf(arg, " %g", &value))
  2418.         {
  2419.             if (scriptWindow)
  2420.             {
  2421.             ObjPtr observer/*, observers*/;
  2422.             observer = FindObserver(scriptWindow);
  2423.             if (!observer) break;
  2424.  
  2425.             SetVar(observer, PITCH, NewReal(value));
  2426.             }
  2427.         }
  2428.         else
  2429.         {
  2430.             ScriptError("An amount to pitch is expected here.");
  2431.         }
  2432.         }
  2433.         break;
  2434.     case KWYAW:
  2435.         {
  2436.         ScriptError("YAW is no longer supported.");
  2437.         }
  2438.         break;
  2439.     case KWROTATE:
  2440.         {
  2441.         char axis;
  2442.         float amount;
  2443.  
  2444.         SHIFTKW(arg, args);
  2445.         if (strlen(arg) == 1 && (*arg == 'x' || *arg == 'y' || *arg == 'z'))
  2446.         {
  2447.             axis = *arg;    
  2448.  
  2449.             SHIFTNUM(arg, args);
  2450.             if (!strlen(arg) || 1 != sscanf(arg, "%f", &amount))
  2451.             {
  2452.             ScriptError("An amount to rotate is expected here.");
  2453.             return true;
  2454.             }
  2455.  
  2456.             if (scriptWindow)
  2457.             {
  2458.             RotateOrthoWindow(scriptWindow, axis, amount);
  2459.             }
  2460.         }
  2461.         else
  2462.         {
  2463.             ScriptError("Unrecognized keyword.  An axis (x, y, or z) is expected.");
  2464.         }
  2465.         return true;
  2466.         }
  2467.         break;
  2468.     case KWSHEAR:
  2469.         ScriptError("Shearing is no longer supported.");
  2470.         return true;
  2471.         break;
  2472.     case KWRECORD:
  2473.         if (FindCommandInStack(KWRECORDING) < 0)
  2474.         {
  2475.         ScriptError("This command can only exist within a BEGIN RECORDING block.");
  2476.         return true;
  2477.         }
  2478.         else
  2479.         {
  2480.         real nSecs;
  2481.         if (1 != sscanf(args, " %g", &nSecs))
  2482.         {
  2483.             
  2484.             ScriptError("A number of seconds to record is expected here.");
  2485.         }
  2486.         else
  2487.         {
  2488.             runningTask = RT_RECORDING;
  2489.             framesLeft = nSecs * 30 + 0.5;
  2490.         }
  2491.         return false;
  2492.         }
  2493.     case KWBEGIN:
  2494.         return BeginCommand(args);
  2495.     case KWEND:
  2496.         return EndCommand(args);
  2497.     case KWSNAP:
  2498.         if (FindCommandInStack(KWRECORDING) < 0)
  2499.         {
  2500.         ScriptError("This command can only exist within a BEGIN RECORDING block.");
  2501.         return true;
  2502.         }
  2503.         PushNonVisWindows();
  2504.         if (!SnapOneFrame())
  2505.         {
  2506.         ScriptError("Could not snap a single frame.");
  2507.         }
  2508.         ++TrashDayFlag;
  2509.         break;
  2510.     case KWWINDOW:
  2511.         SHIFTKW(arg, args);
  2512.         if (!strlen(arg))
  2513.         {
  2514.         ScriptError("The name of a window is expected here");
  2515.         return true;
  2516.         }
  2517.         SelectNamedWindow(arg);
  2518.         break;
  2519.     case KWEXIT:
  2520.     case KWQUIT:
  2521.         DoQuit();
  2522.         break;
  2523.     case KWCLOSE:
  2524.         CloseWindow(scriptWindow);
  2525.         SelWindow(0);
  2526.         scriptWindow = 0;
  2527.         break;
  2528.     case KWPUSHWINDOW:
  2529.         if (scriptWindow)
  2530.         {
  2531.         PushWindow(scriptWindow);
  2532.         }
  2533.         else
  2534.         {
  2535.         ScriptError("There is no current window");
  2536.         }
  2537.         break;
  2538.     case KWSHELL:            /*Shell escape*/
  2539.         SKIPBLANKS(args);
  2540.         if ((getuid() == geteuid()) &&
  2541.         (getgid() == getegid()))
  2542.         {
  2543.             system(args);
  2544.         }
  2545.         break;
  2546.     case KWSCRSAVE:
  2547.         {
  2548.         char fileName[256];
  2549.         int l, r, b, t;
  2550.         int n;
  2551.         n = sscanf(args, " %s %d %d %d %d", fileName, &l, &r, &b, &t);
  2552.         if (n == 5)
  2553.         {
  2554.             sprintf(tempStr, "scrsave %s %d %d %d %d", fileName, l, r, b, t);
  2555.             if ((getuid() == geteuid()) &&
  2556.             (getgid() == getegid()))
  2557.             {
  2558.                 system(tempStr);
  2559.             }
  2560.         }
  2561.         else if (n == 1)
  2562.         {
  2563.             sprintf(tempStr, "scrsave %s", fileName);
  2564.             if ((getuid() == geteuid()) &&
  2565.             (getgid() == getegid()))
  2566.             {
  2567.                 system(tempStr);
  2568.             }
  2569.         }
  2570.         else
  2571.         {
  2572.             ScriptError("A filename and four sides are expected here");
  2573.             return true;
  2574.         }
  2575.         }
  2576.         break;
  2577.     default:
  2578.         ScriptError("This keyword is not a command");
  2579.         break;
  2580.     }
  2581.     return true;
  2582. }
  2583.  
  2584. #ifdef PROTO
  2585. void BeginScript(char *name)
  2586. #else
  2587. void BeginScript(name)
  2588. char *name;
  2589. #endif
  2590. /*Begins a new script opened from file name*/
  2591. {
  2592.     /*Save curScript*/
  2593.     savedScripts[curScriptIndex++] = curScript;
  2594.  
  2595.     curScript = OpenTextFile(name, TF_READ + TF_CONTINUATION);
  2596.     if (curScript)
  2597.     {
  2598.     runningScript = true;
  2599.     abortScript = false;
  2600.     BeginCommand("script");
  2601.     }
  2602.     else
  2603.     {
  2604.     fprintf(stderr, "BeginScript: Cannot open script file %s.\n", name);
  2605.     }
  2606. }
  2607.  
  2608. void EndScript()
  2609. /*Ends a script*/
  2610. {
  2611.     if (curScript)
  2612.     {
  2613.     EndCommand("script");
  2614.  
  2615.     /*Make control panels shown*/
  2616.     ShowScriptControlPanels(true);
  2617.     CloseTextFile(curScript);
  2618.     curScript = savedScripts[--curScriptIndex];
  2619.     if (!curScript)
  2620.     {
  2621.         runningScript = false;
  2622.     }
  2623.     MySetCursor(0);
  2624.     }
  2625. }
  2626.  
  2627. Bool ReadScriptLine()
  2628. /*Reads and does a script line*/
  2629. {
  2630.     if (curScript)
  2631.     {
  2632.     int k, c;
  2633.  
  2634.     if (!lineAccepted)
  2635.     {
  2636.         lineAccepted = InterpretScriptLine(scriptLine);
  2637.         return true;
  2638.     }
  2639.  
  2640.     if (abortScript)
  2641.     {
  2642.         fprintf(stderr, "Aborting script.\n");
  2643.         EndScript();
  2644.         return false;
  2645.     }
  2646.  
  2647.     /*Read a script line*/
  2648.     scriptLine = GetNextLine(curScript);
  2649.     if (!scriptLine)
  2650.     {
  2651.         EndScript();
  2652.         return false;
  2653.     }
  2654.     else
  2655.     {
  2656.         lineAccepted = InterpretScriptLine(scriptLine);
  2657.         return true;
  2658.     }
  2659.     }
  2660.     return true;
  2661. }
  2662.  
  2663. static Bool ScriptTask()
  2664. /*Run the current script task*/
  2665. {
  2666.     switch(runningTask)
  2667.     {
  2668.     case RT_RECORDING:
  2669.         if (framesLeft <= 0)
  2670.         {
  2671.         runningTask = 0;
  2672.         return true;
  2673.         }
  2674.         PushNonVisWindows();
  2675.         if (!SnapOneFrame())
  2676.         {
  2677.         ScriptError("Could not snap a single frame.");
  2678.         }
  2679.         ++TrashDayFlag;
  2680.         --framesLeft;
  2681.         break;
  2682.     }
  2683.     return false;
  2684. }
  2685.  
  2686. Bool InterpretScriptLine(s)
  2687. char *s;
  2688. /*Interprets a script line in character string s.  Returns true iff the script
  2689.   line needs to be thrown away*/
  2690. {
  2691.     char curKeyword[256];
  2692.     int kwn;
  2693.     Bool retVal;
  2694.  
  2695.     if (runningTask != RT_NONE)
  2696.     {
  2697.     /*There's a running task*/
  2698.     return ScriptTask();
  2699.     }
  2700.  
  2701.     /*Look at first keyword*/
  2702.     SKIPBLANKS(s);
  2703.     if (*s == '#')
  2704.     {
  2705.     if (logging)
  2706.     {
  2707.         Log(s);
  2708.         Log("\n");
  2709.     }
  2710.     return true;
  2711.     }
  2712.  
  2713.     if (scriptWindow && IsValidWindow(scriptWindow))
  2714.     {
  2715.     SelWindow(scriptWindow);
  2716.     }
  2717.     else
  2718.     {
  2719.     SelWindow((WinInfoPtr) 0);
  2720.     }
  2721.  
  2722.     if (ObjFunctionScriptLine(s))
  2723.     {
  2724.     retVal = true;
  2725.     }
  2726.     else if (WindowFunctionScriptLine(s))
  2727.     {
  2728.     retVal = true;
  2729.     }
  2730.     else if (RepobjFunctionScriptLine(s))
  2731.     {
  2732.     retVal = true;
  2733.     }
  2734.     else if (CurrentFunctionScriptLine(s))
  2735.     {
  2736.     retVal = true;
  2737.     }
  2738.     else if (GlobalFunctionScriptLine(s))
  2739.     {
  2740.     retVal = true;
  2741.     }
  2742.     else
  2743.     {
  2744.     SHIFTKW(curKeyword, s);
  2745.  
  2746.     if (!strlen(curKeyword))
  2747.     {
  2748.         retVal = true;
  2749.     }
  2750.     else
  2751.     {
  2752.     
  2753.         /*Find out what it is*/
  2754.         kwn = ParseKeyword(curKeyword, keywords, NKEYWORDS);
  2755.         if (kwn == -1)
  2756.         {
  2757.         ScriptError("This command is unknown.");
  2758.         retVal = true;
  2759.         }
  2760.         else if (kwn == -2)
  2761.         {
  2762.         ScriptError("This command is ambiguous.");
  2763.         retVal = true;
  2764.         }
  2765.         else
  2766.         {
  2767.         retVal = DoScriptCommand(kwn, s);
  2768.         }
  2769.     }
  2770.     }
  2771.     return retVal;
  2772. }
  2773.